package ic.doc.co2nudge.client.widgets;

import ic.doc.co2nudge.client.utils.DataServiceFactory;
import ic.doc.co2nudge.client.utils.UserService;
import ic.doc.co2nudge.client.utils.Utils;
import ic.doc.co2nudge.client.utils.events.DataEvent;
import ic.doc.co2nudge.client.utils.events.DataLoadedEventHandler;
import ic.doc.co2nudge.server.PredictionService;
import ic.doc.co2nudge.shared.model.ForecastData;
import ic.doc.co2nudge.shared.model.TransportType;
import ic.doc.co2nudge.shared.model.Trip;
import ic.doc.co2nudge.shared.model.TripOption;
import ic.doc.co2nudge.shared.model.User;
import ic.doc.co2nudge.shared.model.UserData;

import java.awt.Color;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.TreeMap;

import sun.security.krb5.internal.PAData;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.i18n.shared.DateTimeFormat;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.uibinder.client.UiTemplate;
import com.google.gwt.user.client.Random;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.visualization.client.AbstractDataTable;
import com.google.gwt.visualization.client.DataTable;
import com.google.gwt.visualization.client.AbstractDataTable.ColumnType;
import com.google.gwt.visualization.client.visualizations.corechart.AxisOptions;
import com.google.gwt.visualization.client.visualizations.corechart.BarChart;
import com.google.gwt.visualization.client.visualizations.corechart.ColumnChart;
import com.google.gwt.visualization.client.visualizations.corechart.Options;
import com.google.gwt.visualization.client.visualizations.corechart.LineChart;
import com.google.gwt.visualization.client.visualizations.corechart.PieChart;
import com.sun.xml.internal.bind.v2.runtime.unmarshaller.XsiNilLoader.Array;

public class PredictionPanel extends Composite {

	private static PredictionPanelUiBinder uiBinder = GWT
			.create(PredictionPanelUiBinder.class);

	@UiTemplate("PredictionPanel.ui.xml")
	interface PredictionPanelUiBinder extends UiBinder<Widget, PredictionPanel> {
	}
	
	@UiField Button 			btnForecast;
	@UiField Button 			btnAnalysis;
	@UiField VerticalPanel 		pnlChart;
	@UiField VerticalPanel		pnlChartAndGoal;
	
	private LineChart 			lcrtPrediction;
	private ColumnChart 		crtUsersTransport;
	private LineChart			lcrtSavings;
	
	ArrayList<Double> predictedRateSums=
		new ArrayList<Double>();
	
	ArrayList<Double> trendRates=
		new ArrayList<Double>();
	
	ArrayList<Double> yrRateSums=
		new ArrayList<Double>();
	
	HashMap<Integer, Double> tripsMinRates=
		new HashMap<Integer, Double>();
	
	HashMap<Integer, Double> tripsChosenRates=
		new HashMap<Integer, Double>();
	
	public PredictionPanel() {
		initWidget(uiBinder.createAndBindUi(this));
	}

	private AbstractDataTable createDataTable(ForecastData fData) {
		
		int range=12;
		int size=0;
		int period=4;
		
		ArrayList<String> months=
			new ArrayList<String>();
		
		DataTable dataTable=DataTable.create();
		dataTable.addColumn(ColumnType.STRING, "Month");
		dataTable.addColumn(ColumnType.NUMBER, "CO2");
		dataTable.addColumn(ColumnType.NUMBER, "Predicted CO2");
		dataTable.addColumn(ColumnType.NUMBER, "Minimal CO2");
		dataTable.addColumn(ColumnType.NUMBER, "Goal limit");
		dataTable.addRows(range);
		
		DateTimeFormat ff =DateTimeFormat.getFormat("MMM");
		
		//putting months rates to the graph
		for (int i=0; i<range; i++) {
			
			Date date=DateTimeFormat
				.getFormat("MM/yyyy").parse(Integer
						.toString(i+1)+"/2011");
			String strMonth=ff
				.getFormat("MMM").format(date);
		
			dataTable.setValue(i, 0, strMonth);
		}
		
		for (int i=0; i<fData.getForecastStartIndex(); i++) {
			dataTable.setValue(i, 1, 
					Utils.round(fData.getTripsRates().get(i)));
		}

		int index=fData.getForecastStartIndex();
		
		for (int i=index-1; i<range; i++) {
			dataTable.setValue(i, 2, Utils.round( fData.getTripsRates().get(i)));
		}
		
		for (int i=index-1; i<range; i++) {
			dataTable.setValue(i, 3, Utils.round( fData.getMinRates().get(i)));
		}
		
		for (int i=0; i<range; i++) {
			dataTable.setValue(i, 4, Utils.round( fData.getLimitValue()));
		}
		
//		double chosenSum = fData.getTripsRates().get( fData.getTripsRates().size()-1);
//		double minSum = fData.getMinRates().get( fData.getMinRates().size()-1);
//		double percentage = (minSum/chosenSum)*100;
//		double limitValue = chosenSum - (percentage/chosenSum)*100;
//		
//		Window.alert("ChsoenSum " + chosenSum
//				+"\nMinSum " + minSum
//				+"\nPercentage " + percentage
//				+"\nlimitValue " + limitValue);
		
		
		//calculating forecasted rates for the rest of the months
//		int firstForecastedValueIndex=size;
//		for (int i=0; i<range-size; i++) {
//			
//			double nextMonthEmissionRate=PredictionService
//				.calcNextAverageValue(tripsOptionsRates);
//			
//			double nextMonthMinEmissionRate=PredictionService
//				.calcNextAverageValue(minimalCO2Options);
//			
//			int lastIndex=tripsOptionsRates.size();
//			
//			//predictedRateSums.add(nextValue);
//			tripsOptionsRates.put( lastIndex+1, 
//					(Double)tripsOptionsRates
//						.get(lastIndex)+nextMonthEmissionRate);
//		
//			minimalCO2Options.put(lastIndex+1, 
//					(Double)minimalCO2Options
//						.get(lastIndex)+nextMonthMinEmissionRate);
//		}
//				
//		int cur=firstForecastedValueIndex;
//
////		Window.alert(Integer.toString(minimalCO2Options.size()));
//
//		dataTable.setValue(cur-1, 2, Utils
//				.round( tripsOptionsRates.get(cur)));
//		
//		for (int i=cur+1; i<=tripsOptionsRates.size(); i++) {
//			dataTable.setValue(i-1, 2, Utils
//					.round( tripsOptionsRates.get(i)));
////			dataTable.setValue(i, 3, Utils
////					.round( minimalCO2Options.get(i)));			
//		}
//		
//		for (int i=size-1; i<range; i++){
//			dataTable.setValue(i, 3, Utils.round
//					( minimalCO2Options.get(i)));
//		}
	
//		Window.alert(tripsOptionsRates.keySet().toString());
		
//		int goal=400;
//		for (int i=0; i<12; i++) {
//			dataTable.setValue(i, 4, goal);
//		}
		
		return dataTable;
	}
	
	private Options createOptions(){
		Options options=Options.create();
		options.setWidth(400);
		options.setHeight(340);
		options.setFontSize(11D);
		options.setFontName("Tahoma");
		options.setGridlineColor("lightgrey");
		options.setBackgroundColor("white");
		options.setColors("purple", "blue", "green", "red", "brown");
		options.setLineWidth(1);
		options.setCurveType("function");
		options.setTitle("Carbon emissions prediction graph (in kg)");
		
		return options;
	}
		
	private AbstractDataTable createOverallViewChartDataTable(List<Trip> data){
		
		DataTable dataTable=DataTable.create();
		StringBuilder years=new StringBuilder();
		
		DateTimeFormat f=DateTimeFormat
			.getFormat("yyyy");

		String strBaseYear= f.format( data.get(0).getDate());
		double sum=data.get(0).getChosenCO2Option().getRate();
		
		for ( int i=1; i<data.size(); i++) {
			
			String strYear=f.format(data.get(i).getDate());
			
			if (!strBaseYear.equals(strYear)) {
				yrRateSums.add( Utils.round( sum));
				years.append(strBaseYear+";");
				
				strBaseYear=strYear;	
				sum=0.0;
			}
			sum+=data.get(i).getChosenCO2Option().getRate();
		}
		
		if (years.indexOf(strBaseYear)<0){
			yrRateSums.add( Utils.round( sum));
			years.append(strBaseYear+";");
		}
		
		int index= yrRateSums.size()-1;
		double predictedRatesSum=yrRateSums.get(index);
		for (Double d: trendRates){
			predictedRatesSum+=d;
		}
		
		dataTable.addColumn(ColumnType.STRING, "Year");
		dataTable.addColumn(ColumnType.NUMBER, "Current CO2");
		dataTable.addColumn(ColumnType.NUMBER, "Predicted CO2");
		dataTable.addColumn(ColumnType.NUMBER, "Minimal CO2");
		
		dataTable.addRows(yrRateSums.size());
		
		String strYars=years.toString();
		String[] arrayOfYears=strYars.split(";");
		Arrays.sort(arrayOfYears);
		
		for (int i=0; i<arrayOfYears.length; i++) {
			dataTable.setValue(i, 0, arrayOfYears[i]);
			dataTable.setValue(i, 1, yrRateSums.get(i));
		}
		
		dataTable.setValue(index, 2, Utils.round(predictedRatesSum));
		dataTable.setValue(index, 3, Utils
				.calcCO2EmissionsBorder(yrRateSums.get(index-1), 10));
		
		return dataTable;
	}
	
	protected AbstractDataTable createUsersTransportTable(HashMap<Long, 
			Integer> tData) {
		
		if (tData==null)
			return null;
		
		String str="";
		
		DataTable dataTable= DataTable.create();
		dataTable.addColumn(ColumnType.STRING, "Transport type");
		dataTable.addColumn(ColumnType.NUMBER, "Most used transport type");
		dataTable.addRows(tData.size());
		
		int curIndex=0;
	
		for (Long id: tData.keySet()) {		
			
			TransportType type=DataServiceFactory
				.getTransportTypeById(id);
			
			dataTable.setValue(curIndex, 0, type.getName());
			dataTable.setValue(curIndex, 1, tData.get(id));
			curIndex++;	
		}
		return dataTable;
	}
	
	
	protected Options createUserTransportDataTableOptions() {
		Options options=Options.create();
		options.setBackgroundColor("lightgray");
		options.setLineWidth(1);
		options.setWidth(120);
		options.setHeight(80);
		options.setFontSize(11D);
		options.setFontName("Tahoma");
		options.setGridlineColor("lightgrey");
		
		return options;
	}
	
	protected Options createDataTableOptions(){
		Options options=Options.create();
		options.setBackgroundColor("white");
		options.setColors(
				"green", 
				"orange");
		
		options.setLineWidth(1);
		options.setPointSize(1);
		options.setWidth(320);
		options.setHeight(280);
		options.setFontSize(11D);
		options.setFontName("Tahoma");
		options.setGridlineColor("lightgrey");
		
		return options;
	}
	
	protected Options createTransportTypesChartOptions() {
		
		Options options=Options.create();
		
		options.setBackgroundColor("white");
		options.setColors(
				"green", 
				"blue",
				"orange");
		
		options.setWidth(250);
		options.setHeight(140);
		options.setFontSize(11D);
		options.setFontName("Tahoma");
		options.setGridlineColor("lightgrey");
		
		return options;		
	}
	
	protected AbstractDataTable createSavingsDataTable(List<UserData> uData) {
		
		if (uData==null)
			return null;
	
		UserData[] usersData= 
			uData.toArray( new UserData[0]);
		
		Arrays.sort( usersData, new Comparator<UserData>() {

			@Override
			public int compare(UserData ud1, UserData ud2) {
				return (ud1.getSavingsSum()>ud2.getSavingsSum())?1:0;
			}
		});
		
		DataTable dataTable= DataTable.create();
		dataTable.addColumn(ColumnType.STRING, "Person");
		dataTable.addColumn(ColumnType.NUMBER, "Savings");
		dataTable.addRows(uData.size());
		
		int curIndex=0;
		for (UserData u: usersData) {
			dataTable.setValue(curIndex, 0, u.getUser().getName());
			dataTable.setValue(curIndex, 1, Utils.round( u.getSavingsSum()));
			curIndex++;
		}
		
		return dataTable;
	}
	
	@UiHandler("btnForecast")
	public void btnSingleUserForecastClick(ClickEvent e){
		
    	pnlChart.clear();
    	
    	DataServiceFactory.removeDataLoadedListener();
    	DataServiceFactory.addDataLoadedListener( new DataLoadedEventHandler(){
  
    		@Override
    		public void dataLoaded(DataEvent e) {
    			
    			if ((e!=null)&&(e.getData()!=null)){
    				
    				ForecastData fData=(ForecastData)e.getData();
    				
    				lcrtPrediction=
    					new LineChart( createDataTable(fData), createOptions());
    				
    				pnlChartAndGoal.setVisible(true);
    				pnlChart.add(lcrtPrediction);
    				
    				DataServiceFactory.removeDataLoadedListener();
    			}
    		}
    	});
    	
    	DataServiceFactory.loadPredictionData(UserService.
    			getUserService().getCurrentUser());
	}    	
	
	@UiHandler("btnAnalysis")
	public void btnAnalysis(ClickEvent e) {
		
		DataServiceFactory.removeDataLoadedListener();
		
		DataServiceFactory.addDataLoadedListener(
				new DataLoadedEventHandler(){
					
					@Override
					public void dataLoaded(DataEvent e) {
						
						if (e.getData()!=null) {
							
							List<UserData> uData=(List<UserData>)e.getData();
							
							pnlChart.clear();
							
							Options options=createDataTableOptions();
							options.setTitle("Carbon savings made by users");
							options.setWidth(400);
							
							lcrtSavings=new LineChart( createSavingsDataTable( uData), options);
		
							pnlChart.add( createTransportTypesGrid(uData));
							pnlChart.add( lcrtSavings);
						}
					}
				}
		);	
		DataServiceFactory.loadAnalysisData();	
	}	
	
	private FlexTable createTransportTypesGrid(List<UserData> usersData) {
		
		FlexTable grid=new FlexTable();
		
		int curIndex=0;
		for (UserData uData: usersData) {
			
			Options options=createTransportTypesChartOptions();
			options.setTitle(uData.getUser().getName());
			
			PieChart pchrtTransportTypes=
				new PieChart( createUsersTransportTable(uData
						.getTransportTypes()), 
						options);
			
			grid.setWidget(0, curIndex, 
					pchrtTransportTypes);
			curIndex++;
		}
		
		grid.addStyleName("flextable");
		return grid;
	}	
}